package com.sndscl.rpc.netty;

import com.sndscl.rpc.common.constant.SndSclConstant;
import com.sndscl.rpc.common.dto.RpcRequest;
import com.sndscl.rpc.common.dto.RpcResponse;
import com.sndscl.rpc.spring.SndSclBeanPostProcessor;
import com.sndscl.rpc.spring.SpringApplicationContextUtils;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Set;

/**
 * @Description
 * @Author lsh
 * @Date 2020/10/13 15:00
 **/
public class RequestHandler extends SimpleChannelInboundHandler<RpcRequest> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RpcRequest rpcRequest) {

        RpcResponse rpcResponse = new RpcResponse();
        rpcResponse.setType(rpcRequest.getType());
        if("00".equals(rpcRequest.getType())){
            //保持心跳
            rpcResponse.setRetCode(00);
        }else{
            rpcResponse.setId(rpcRequest.getId());
            String className = rpcRequest.getClassName();
            String methodName = rpcRequest.getMethodName();
            Object[] args = rpcRequest.getArgs();
            //判断 接口是否存在
            Set<String> interfaces = SndSclBeanPostProcessor.getInterfaceList();
            if(!interfaces.contains(rpcRequest.getMethodSign())){
                rpcResponse.setRetCode(404);
                ctx.writeAndFlush(rpcResponse);
                return;
            }
            String beanName = SndSclBeanPostProcessor.getBeanName(className);
            if(beanName == null ){
                rpcResponse.setRetCode(407);
                ctx.writeAndFlush(rpcResponse);
                return;
            }
            Object service = SpringApplicationContextUtils.getBean(beanName);
            if(service == null){
                rpcResponse.setRetCode(409);
                ctx.writeAndFlush(rpcResponse);
                return;
            }
            Method method = null;
            try {
                method = service.getClass().getDeclaredMethod(methodName,rpcRequest.getParameterTypes());
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            if(method == null){
                rpcResponse.setRetCode(410);
                ctx.writeAndFlush(rpcResponse);
                return;
            }
            try {
                rpcResponse.setResult(method.invoke(service,args));
                rpcResponse.setRetCode(200);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                rpcResponse.setRetCode(444);
            } catch (InvocationTargetException e) {
                e.printStackTrace();
                rpcResponse.setRetCode(445);
            }
        }
        ctx.writeAndFlush(rpcResponse);
        ctx.writeAndFlush(Unpooled.copiedBuffer(SndSclConstant.NETTY_DELIMITER.getBytes()));
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //客户端退出
        ctx.channel().close();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.channel().close();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if(evt instanceof IdleStateEvent){
            //
            switch (((IdleStateEvent) evt).state()){
                case READER_IDLE:
                    System.out.println("Server read timeout ...");
                    ctx.close();
                    break;
                case WRITER_IDLE:
                    break;
                case ALL_IDLE:
                    break;
                default:
                    break;
            }
        }
    }
}
